package
{
	import as3isolib.display.IsoSprite;
	import as3isolib.display.IsoView;
	import as3isolib.display.primitive.IsoBox;
	import as3isolib.display.primitive.IsoHexBox;
	import as3isolib.display.scene.IsoGrid;
	import as3isolib.display.scene.IsoScene;
	import as3isolib.geom.IsoMath;
	import as3isolib.geom.Pt;
	
	import com.adobe.crypto.MD5;
	
	import de.polygonal.math.PM_PRNG;
	
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.system.Security;
	import flash.utils.Timer;
	import flash.utils.getTimer;
	
	public class space extends Sprite
	{
		public static const PPS:int = 50;
		public static const SECTOR_SIZE:int = PPS*50;
		public static const PLANET_DENSITY:int = 1500;
		public static const PLANET_SIZE:int = 100;
		private var _view:IsoView;
		private var _scene:IsoScene;
		private var _box:IsoBox;
		private var _follower:IsoBox;
		
		public var currentVisibleSectors:Vector.<Sector> = new Vector.<Sector>;
		
		private var _grid:IsoGrid;
		//private var m_testTimer:Timer = new Timer(250);
		private var m_cameraTicker:Timer = new Timer(1000/30);
		private var m_gameTicker:Timer = new Timer(1000/30);
		
		private var m_sectorCleanupTimer:Timer = new Timer(1000);
	
		
		private var starfield:ParallaxStarfield = new ParallaxStarfield();
		public function space()
		{

			addChild(starfield);
//			starfield.x += stage.width/4;
//			starfield.y += stage.height/4;			
			
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			stage.color = 0;

			_view = new IsoView();
			_view.setSize( stage.stageWidth, stage.stageHeight );
			addChild( _view );
			
			_scene = new IsoScene();
			_scene.hostContainer = this;
			_view.addScene( _scene );
			
			_box = new IsoBox();
			_box.setSize( PPS, PPS, PPS );
			_scene.addChild( _box );
			_box.autoUpdate = true;
			
			_follower = new IsoBox();
			_follower.setSize( PPS/5, PPS/5, PPS/5 );
			_scene.addChild( _follower );
			
			_grid = new IsoGrid();
			_grid.setGridSize(20,20);
			_grid.cellSize = PPS;
	//		_scene.addChild( _grid );
			
			m_sectorCleanupTimer.addEventListener(TimerEvent.TIMER, function():void{
				var i:int, il:int, j:int, jl:int;
				for(i = 0, il = m_sectors.length; i < il; i++){
					var surroundingSectors:Vector.<Sector> = getSurroundingSectors(getSector(new Point(_box.x, _box.y)));
					for(j = 0, jl = surroundingSectors.length; j < jl; j++){
						if(surroundingSectors.indexOf(m_sectors[i]) == -1){
							var deltaTime:int = getTimer() - m_sectors[i].lastTimeUpdated;
							if(deltaTime > 2000){
								m_sectors[i].destroyFlag = true;
							}
						}
					}
				}
				
				var newSectors:Vector.<Sector> = new Vector.<Sector>;
				for(i = 0, il = m_sectors.length; i < il; i++){
					if(m_sectors[i].destroyFlag == false){
						newSectors.push(m_sectors[i]);
					} else {
						m_sectors[i].hidePlanets();
					}
				}
				
				m_sectors = newSectors;
			});
			
			
			m_sectorCleanupTimer.start();
			
//			var i:int, il:int;
//			var planetLocations:Vector.<Point> = generatePlanetLocations(new Point(0,0),10*PPS,5);
//			for(i = 0, il = planetLocations.length; i < il; i++){
//				var planet:IsoBox = new IsoBox();
//				planet.setSize( 10, 10, 10 );
//				planet.x = planetLocations[i].x;
//				planet.y = planetLocations[i].y;
//				planets.push(planet);
//				_scene.addChild( planet );				
//			}
			
			var cameraDistanceToTravel:Number = 0;
			
			m_cameraTicker.addEventListener(TimerEvent.TIMER, function():void{
				if(autoPan == false){
					return;
				}
				
				//var viewPos:Point = new Point(_view.currentX, _view.currentY);
				var boxPos:Point = new Point(_box.x, _box.y);
				var followerPos:Point = new Point(_follower.x, _follower.y);
				var delta:Point = boxPos.subtract(followerPos);
				
				if(delta.length >= 0.1){
					
					var moveBy:Point = new Point(delta.x*.1, delta.y*.1);
					_follower.moveBy(moveBy.x, moveBy.y,0);
					var screenDelta:Pt = IsoMath.isoToScreen(new Pt(delta.x*.01, delta.y*.01),true);
					starfield.change(new Point(-screenDelta.x, -screenDelta.y));					
					_view.centerOnIso(_follower);
					
					cameraDistanceToTravel -= moveBy.length;
				}
			});
			m_cameraTicker.start();
			
			var distanceToTravel:Number = 0;
			
			m_gameTicker.addEventListener(TimerEvent.TIMER, function():void{
				var boxPos:Point = new Point(_box.x, _box.y);
				var delta:Point = finalDestination.subtract(boxPos);
				var currentPosition:Point = new Point(_box.x, _box.y);
				
				if(distanceToTravel >= 0){
					delta.normalize(1);
					var moveBy:Point = new Point(delta.x*10, delta.y*10);
					_box.moveBy(moveBy.x, moveBy.y, 0);
					distanceToTravel -= moveBy.length;
				}
				
				var nextSector:Sector = getSector(new Point(_box.x, _box.y));
				if(!nextSector.rectangle.equals(getSector(currentPosition).rectangle)){
					updateDisplay(nextSector);	
				}				
				
				_scene.render(true);
			});
			m_gameTicker.start();			
			
			var enemy:IsoBox = new IsoBox();
			enemy.setSize( 25, 25, 25 );
			_scene.addChild( enemy );	
			enemy.autoUpdate = true;
			
			var downPoint:Point;
			var totalDragDistance:Number = 0;
			var finalDestination:Point = new Point(_box.x, _box.y);
			var autoPan:Boolean = true;
			stage.addEventListener(MouseEvent.MOUSE_DOWN, function(me:MouseEvent):void{
				downPoint = new Point(me.stageX, me.stageY);
			});
			
			stage.addEventListener(MouseEvent.MOUSE_UP, function(me:MouseEvent):void{
				if(totalDragDistance <= 1){
					finalDestination = _view.localToIso(downPoint);
					var boxPos:Point = new Point(_box.x, _box.y);
					var delta:Point = finalDestination.subtract(boxPos);
					distanceToTravel = delta.length;
					cameraDistanceToTravel = delta.length;
					autoPan = true;
					
					var clampedFinalDestination:Point = new Point(Math.floor(finalDestination.x), Math.floor(finalDestination.y));
					var enemyPos:Point = new Point(enemy.x, enemy.y);
					if(!enemyPos.equals(clampedFinalDestination)){
						enemy.moveTo(clampedFinalDestination.x, clampedFinalDestination.y, 0);
					}
				}
				totalDragDistance = 0;
				downPoint = null;
				
			});				
			stage.addEventListener(MouseEvent.MOUSE_MOVE, function(me:MouseEvent):void{
				if(downPoint){
					var curpoint:Point = new Point(me.stageX, me.stageY);
					var delta:Point = downPoint.subtract(curpoint);
					totalDragDistance += delta.length;
					_view.panBy(delta.x, delta.y);
					downPoint = curpoint;
					autoPan = false;
				}
			});
			
			
			updateDisplay(getSector(new Point(0,0)));
			_scene.render(true);
			
		}
		
		private var m_sectors:Vector.<Sector> = new Vector.<Sector>;
		
		public function updateDisplay(sector:Sector):void{
			var surroundingSectors:Vector.<Sector> = getSurroundingSectors(sector);
			var sectorsThatNeedUpdating:Vector.<Sector> = new Vector.<Sector>;
			var i:int, il:int, j:int, jl:int;
			var isIn:Boolean = false;
			for(i = 0, il = surroundingSectors.length; i < il; i++){
				surroundingSectors[i].lastTimeUpdated = getTimer();
				if(m_sectors.indexOf(surroundingSectors[i]) == -1){
					m_sectors.push(surroundingSectors[i]);
					showPlanets(surroundingSectors[i]);
				}
				
			}
			
			//_scene.render(true);
		}
		
		public function getSurroundingSectors(sector:Sector):Vector.<Sector>{
			var sectors:Vector.<Sector> = new Vector.<Sector>;
			var surroundingSector:Sector;
			var i:int, j:int;
			for(i = -1; i < 2; i++){
				for(j = -1; j < 2; j++){
					var sectorLocation:Point = new Point(i*SECTOR_SIZE + sector.rectangle.x, j*SECTOR_SIZE + sector.rectangle.y);
					surroundingSector = findSector(sectorLocation);
					if(surroundingSector == null){
						surroundingSector = new Sector(new Rectangle(sectorLocation.x, sectorLocation.y, SECTOR_SIZE, SECTOR_SIZE));
					}
					sectors.push(surroundingSector);
				}
			}
			
			return sectors;
		}
		
		public function findSector(point:Point):Sector{
			var i:int, il:int;
			for(i = 0, il = m_sectors.length; i < il; i++){
				if(m_sectors[i].rectangle.topLeft.equals(point)){
					return m_sectors[i];
				}
			}
			
			return null;
		}
		
		public function showPlanets(sector:Sector):void{
			
				var i:int, il:int;
				var planetLocations:Vector.<Point> = generatePlanetLocations(new Point(sector.rectangle.x, sector.rectangle.y),SECTOR_SIZE,PLANET_DENSITY);
				for(i = 0, il = planetLocations.length; i < il; i++){
					//var planet:IsoBox = new IsoBox();
					var ldr:Loader = new Loader();
					ldr.load(new URLRequest('http://www.clker.com/cliparts/3/1/b/a/11971488211294199438barretr_Earth.svg.med.png'));
					ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void{
						var img:DisplayObject = (e.currentTarget as LoaderInfo).loader.content; 
						img.x = -img.width/2;
						img.y = -img.height/2;
					});
					var planet:IsoSprite = new IsoSprite();
					planet.container.addChild(ldr);
					planet.setSize( PLANET_SIZE, PLANET_SIZE, PLANET_SIZE );
					planet.x = planetLocations[i].x;
					planet.y = planetLocations[i].y;
					sector.planets.push(planet);
					_scene.addChild( planet );	
				}
				
				
		}
		
		public function getSector(pnt:Point):Sector{
			var sectorPoint:Point = new Point(Math.floor(pnt.x / SECTOR_SIZE)*SECTOR_SIZE,Math.floor(pnt.y / SECTOR_SIZE)*SECTOR_SIZE);
			var sector:Sector = new Sector(new Rectangle(sectorPoint.x, sectorPoint.y, SECTOR_SIZE, SECTOR_SIZE));
			return sector;
		}
		
		public function generatePlanetLocations(loc:Point, distance:int=50*PPS, density:int=1000):Vector.<Point>{
			var i:int, j:int;
			var universeRect:Rectangle = new Rectangle(loc.x, loc.y, distance, distance);
			var test:Object = new Object();
			var locations:Vector.<Point> = new Vector.<Point>;
			var counter:int = 0;
			var seed:String;
			var pr:PM_PRNG = new PM_PRNG;
			pr.seed = loc.x * 1000 + loc.y;
			
			for(i = universeRect.left; i < universeRect.right; i += PPS){
				for(j = universeRect.top; j < universeRect.bottom; j += PPS){
					seed = String(i) + ',' + String(j);
					var rand:int = Math.floor(pr.nextDouble()*density);
					if(rand == 1){
						locations.push(new Point(i,j));
					}
					
				}
			}
			
			
			
			return locations;
		}
		
		// inclusive
		public static function seededRandBetween(seed:String, min:int, max:int):int{
			var delta:int = max - min + 1;
			var hash:String = "0x"+MD5.hash(seed).substring(0,8);
			var hashNumber:Number = Number(hash);
			var remainder:int = hashNumber % delta;
			var result:int = remainder + min;
			return result;
		}		
	}
}